﻿using LiteDB;
using Microsoft.Extensions.Logging;
using Microsoft.WindowsAPICodePack.Dialogs;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Windows;
using VIA.Domain;
using VIA.Foundation;
using VIA.Presentation;
using VIA.Presentation.Contracts;
using VIA.Project.Domain.Services;
using VIA.SiMoJi.Domain.Vision;

namespace VIA.Project.Presentation.ViewModel.Inspection
{
    [ViewModel(typeof(IProductionRecordView))]
    class ProductionRecordViewModel : ViewModel<IProductionRecordView>
    {
        #region Fields
        bool _isRunning;
        int _totalPage;
        int _rowsPerPage = 40;
        int _currentPage;
        int _totalCount;
        string searchText;
        DateTime? _startTime = DateTime.Now.AddDays(-1);
        DateTime? _endTime;
        private IEnumerable<Product> serchedProducts;
        private Product selectedProduct;
        private string selectedLiteDb = "已完成";
        private string folderPath;
        private readonly ICommandFactory _commandFactory;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IMessageService _messageService;
        private readonly ICsvStorageService _csvStorageService;
        private readonly ILocalDatabaseService _localDatabaseService;
        private readonly ILogger _logger;
        private readonly IRecordService<Product> _recordService;

        #endregion

        #region Commands

        public IRelayCommand SearchCommand { get; }
        public IRelayCommand FirstPageCommand { get; }
        public IRelayCommand LastPageCommand { get; }
        public IRelayCommand NextPageCommand { get; }
        public IRelayCommand PreviousPageCommand { get; }
        public IRelayCommand BrowseDetailCommand { get; }
        public IRelayCommand SaveSelectedCommand { get; }

        #endregion

        #region Properties

        public CultureInfo CultureInfo { get; set; } = new CultureInfo("zh-CN");
        public bool IsRunning
        {
            get => _isRunning;
            set
            {
                if (SetProperty(ref _isRunning, value))
                {
                    try
                    {
                        View.Dispatcher.Invoke(() => _commandFactory.RaiseCanExecuteChanged());
                    }
                    catch (Exception e)
                    {

                    }
                }
            }
        }
        public int TotalPage
        {
            get => _totalPage;
            set => SetProperty(ref _totalPage, value);
        }
        public int TotalCount
        {
            get => _totalCount;
            set => SetProperty(ref _totalCount, value);
        }
        public int RowsPerPage
        {
            get => _rowsPerPage;
            set
            {
                if (SetProperty(ref _rowsPerPage, value))
                {
                    Update();
                }
            }
        }

        public int CurrentPage
        {
            get => _currentPage;
            set
            {
                SetProperty(ref _currentPage, value);
                Refresh();
            }
        }
        public string SearchText
        {
            get => searchText;
            set => SetProperty(ref searchText, value);
        }
        public DateTime? StartTime
        {
            get => _startTime;
            set => SetProperty(ref _startTime, value);
        }
        public DateTime? EndTime
        {
            get => _endTime;
            set => SetProperty(ref _endTime, value);
        }

        public string FolderPath { get => folderPath; set => SetProperty(ref folderPath, value); }
        public string SelectedLiteDb { get => selectedLiteDb; set => SetProperty(ref selectedLiteDb, value); }
        public ObservableCollection<Product> Products { get; set; } = new ObservableCollection<Product>();
        public Product SelectedProduct { get => selectedProduct; set => SetProperty(ref selectedProduct, value); }
        public IEnumerable<Product> SerchedProducts { get => serchedProducts; private set { serchedProducts = value; } }

        #endregion

        public ProductionRecordViewModel(ICommandFactory commandFactory, IUnitOfWorkManager unitOfWorkManager, ILogger<ProductionRecordViewModel> logger, IMessageService messageService, ICsvStorageService csvStorageService, ILocalDatabaseService localDatabaseService, IRecordService<Product> recordService)
        {
            _logger = logger;
            _messageService = messageService;
            _csvStorageService = csvStorageService;
            _localDatabaseService = localDatabaseService;
            _recordService = recordService;
            _unitOfWorkManager = unitOfWorkManager;
            _commandFactory = commandFactory;
            StartTime = DateTime.Now.AddDays(-1);
            FirstPageCommand = commandFactory.Create(() => CurrentPage = 1, () => CurrentPage != 1 && !_isRunning);
            LastPageCommand = commandFactory.Create(() => CurrentPage = TotalPage, () => CurrentPage != TotalPage && !_isRunning);
            NextPageCommand = commandFactory.Create(() => CurrentPage++, () => CurrentPage < TotalPage && !_isRunning);
            PreviousPageCommand = commandFactory.Create(() => CurrentPage--, () => CurrentPage > 1 && !_isRunning);
            SearchCommand = commandFactory.Create(Search);
            BrowseDetailCommand = commandFactory.Create(BrowseDetail);
            SaveSelectedCommand = commandFactory.Create(SaveSelected);
        }

        #region Fuction

        private ILiteCollection<Product> GetLiteCollection()
        {
            return _localDatabaseService.GetCollection<Product>("Product");
        }

        void Search()
        {
            FindFromDB();
            Update();
        }

        void FindFromDB()
        {
            IsRunning = true;
            try
            {
                Stopwatch sw = Stopwatch.StartNew();
                var collection = _recordService.Products;
                using (_unitOfWorkManager.Create())
                {
                    var start = StartTime == null ? DateTime.UnixEpoch : StartTime;
                    var end = EndTime == null ? DateTime.Now : EndTime;
                    collection.EnsureIndex(x => x.CreateTime);
                    var list = collection.Find(x => x.CreateTime >= start && x.CreateTime <= end);
                    if (!SearchText.IsNullOrEmpty())
                    {
                        list = list.Where(x => x.Barcode.Contains(SearchText));
                    }
                    list = list.OrderByDescending(x => x.CreateTime);
                    SerchedProducts = list;
                    sw.Stop();
                }
            }
            catch (Exception e)
            {
                SerchedProducts = null;
                _logger.LogError(e, e.Message);
                _messageService.ShowError(e);
            }
            finally
            {
                IsRunning = false;
            }
        }

        void Update()
        {
            TotalCount = SerchedProducts.Count();
            TotalPage = (int)Math.Ceiling(TotalCount / (double)RowsPerPage);
            if (TotalPage == 0)
                CurrentPage = 0;
            else
                CurrentPage = 1;
        }

        private void Refresh()
        {
            try
            {
                if (SerchedProducts == null)
                {
                    View.Dispatcher.Invoke(() =>
                    {
                        Products.Clear();
                        _commandFactory.RaiseCanExecuteChanged();
                    });
                }
                else
                {
                    var results = SerchedProducts.PageBy((_currentPage - 1) * _rowsPerPage, _rowsPerPage).ToObservableCollection();
                    View.Dispatcher.Invoke(() =>
                    {
                        Products?.Clear();
                        Products.AddRange(results);
                        _commandFactory.RaiseCanExecuteChanged();
                    });
                }
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _messageService.ShowError(e);
            }

        }

        async void BrowseDetail()
        {
            if (SelectedProduct == null) return;
            IsRunning = true;
            try
            {
                var collection = _recordService.Products;

                await View.Dispatcher.InvokeAsync(() =>
                {
                    _commandFactory.RaiseCanExecuteChanged();
                });
            }
            catch (Exception e)
            {
                _logger.LogError(e, e.Message);
                _messageService.ShowError(e);
            }
            finally
            {
                IsRunning = false;
            }

        }

        private async void SaveSelected()
        {
            try
            {
                if (SerchedProducts == null) return;
                if (string.IsNullOrEmpty(FolderPath) && Select())
                {
                    string file = $"{FolderPath}\\{DateTime.Now:yyyy-MM-dd HH.mm.ss}.csv";
                    foreach (Product item in SerchedProducts)
                    {
                        await _csvStorageService.SaveAsync(item, file);
                    }
                    MessageBox.Show($"成功导出到：{file}");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"导出失败：{ex.Message}");
            }
        }

        private bool Select()
        {
            CommonOpenFileDialog dialog = new CommonOpenFileDialog();
            dialog.IsFolderPicker = true;
            dialog.RestoreDirectory = true;
            string folder = Environment.CurrentDirectory;
            folder = Path.Combine(folder, "Data");
            dialog.InitialDirectory = folder;
            if (dialog.ShowDialog() == CommonFileDialogResult.Ok)
            {
                var dic = Directory.CreateDirectory(dialog.FileName);
                FolderPath = dialog.FileName;
                return true;
            }
            return false;
        }

        #endregion
    }
}
